package com.example.ormsqlsplicingframe1.processor;

import cn.hutool.core.util.StrUtil;
import com.example.ormsqlsplicingframe1.orm.note.TableFieldKey;
import com.example.ormsqlsplicingframe1.orm.note.Title;
import com.example.ormsqlsplicingframe1.orm.note.Translate;
import com.example.ormsqlsplicingframe1.session.SqlPostProcessor;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;

import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Optional;

public class TranslatePostProcessor implements SqlPostProcessor {
    private String sql = "";
    private String from = "";
    private HashSet<String> columns = new HashSet<String>();
    private Integer count = 0;
    private String id;
    private Class<?> meteClass;

    @Override
    public String enhance(String sql, Class<?> clazz) {
        this.sql = sql;
        this.meteClass = clazz;
        try {
            return sqlBuilder();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public String sqlBuilder() throws IOException {
        findAnnotation(meteClass);
        String tableName = "";
        if (meteClass == null) {
            throw new RuntimeException("meteClass Cannot be empty");
        }
        if (count > 0 && StrUtil.isEmpty(id)) {
            throw new RuntimeException("TableFieldKey Cannot be empty");
        } else if (StrUtil.isBlank(from)) {
            return sql;
        }
        CachingMetadataReaderFactory cachingMetadataReaderFactory = new CachingMetadataReaderFactory();
        MetadataReader metadataReader = cachingMetadataReaderFactory.getMetadataReader(meteClass.getName());
        if (metadataReader.getAnnotationMetadata().hasAnnotation(Title.class.getName())) {
            Optional<Object> titleName = metadataReader.getAnnotationMetadata().getAnnotations().get(Title.class.getName()).getValue("titleName");
            if (titleName.isPresent()) {
                String titleNameStr = (String) titleName.get();
                if (titleNameStr.contains("as")) {
                    tableName = titleNameStr.split("as")[1];
                } else if (titleNameStr.contains(" ")) {
                    tableName = titleNameStr.split(" ")[1];
                } else {
                    tableName = titleNameStr;
                }
            }
        }
        if (StrUtil.isBlank(tableName)) {
            tableName = StrUtil.toUnderlineCase(meteClass.getName());
        }
        String[] param = new String[count];
        Arrays.fill(param, id);
//
        String[] segmentation = sql.split("from");
        String befroFrom = segmentation[1];
        sql = sql.replace(befroFrom, befroFrom.replaceFirst(tableName, String.format("%s %s", tableName, String.format(from, param))));
        return sql;

    }

    void findAnnotation(Class<?> clazz) {
        Class<?> superclass = clazz.getSuperclass();
        if (superclass == null) return;
        findAnnotation(superclass);
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (declaredField.getAnnotation(TableFieldKey.class) != null) {
                if (StrUtil.isNotBlank(id)) {
                    throw new RuntimeException("TableFieldKey Cannot repeat");
                }
                id = StrUtil.toUnderlineCase(declaredField.getName());
            }
            Translate tran = declaredField.getAnnotation(Translate.class);
            if (tran != null) {
                String fieldName = tran.fieldName();
                String tableName = tran.tableName();
                selectBuilder(declaredField.getName(),tableName);
                fromBuilder(tableName, fieldName);
            }

        }

    }

    private void fromBuilder(String tableName, String fieldName) {
        if (columns.contains(tableName)) {
            return;
        }
        // TODO 有个问题 目前这种写法是不支持 select *,a.a,b.b from c join a on a.id=c.id join a as b on b.id=b.id  这种写法
        if (StrUtil.isBlank(fieldName)) {
            count++;
            fieldName = "%s";
        }
        columns.add(tableName);
        from = from + String.format("left join %s on %s = %s.id", tableName, fieldName, tableName);
    }

    void selectBuilder(String name, String tableName) {
        sql = sql.replace("from", String.format(",%s.%s as %s from", tableName,StrUtil.toUnderlineCase(name), name));
    }

}
